package com.unitd.frame.sso.web.interceptor;

import com.unitd.frame.sso.annotation.Action;
import com.unitd.frame.sso.annotation.Permission;
import com.unitd.frame.sso.common.config.SSOConfig;
import com.unitd.frame.sso.common.helper.SSOHelper;
import com.unitd.frame.sso.common.token.SSOToken;
import com.unitd.frame.comm.utils.http.HttpUtils;
import com.unitd.frame.sso.service.auth.ISSOAuthorization;
import com.unitd.frame.comm.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @desc SSO 权限拦截器（必须在 sso 拦截器之后执行）
 * @filename SSOPermissionInterceptor.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2016/10/18
 */
public class SSOPermissionInterceptor extends HandlerInterceptorAdapter {

	private static final Logger logger = LoggerFactory.getLogger(SSOPermissionInterceptor.class.getName());

	/* 系统权限授权接口 */
	private ISSOAuthorization authorization;
	/* 非法请求提示 URL */
	private String illegalUrl;

	/**
	 * @desc 用户权限验证
	 * 执行登录权限验证,此方法在调用SprigMVC的Controller的处理方法之前进行拦截调用
	 * @param request http请求对象
	 * @param response http响应对象
	 * @param handler 默认的SSO Handler拦截器
	 * @return 登录用户是否有权限
	 * @throws Exception
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if (handler instanceof HandlerMethod) {
			SSOToken token = SSOHelper.attrToken(request);
			if (token == null) {
				return true;
			}

			/* 权限验证是否合法 */
			if (isVerification(request, handler, token)) {
				return true;
			}

			/* 验证不通过,无权限访问 */
			return unauthorizedAccess(request, response);
		}
		return true;
	}


	/**
	 * @desc 判断权限是否合法,支持 1、请求地址 2、注解编码
	 * @param request http请求对象
	 * @param handler 默认的SSO Handler拦截器
	 * @param token 当前请求的用户token
	 * @return 登录用户是否有权限
	 */
	protected boolean isVerification(HttpServletRequest request, Object handler, SSOToken token) {
		/* URL 权限认证 */
		if (SSOConfig.getInstance().isPermissionUri()) {
			String uri = request.getRequestURI();
			if (uri == null || authorization.isPermitted(token, uri)) {
				return true;
			}
		}

		/*排除工作流相关*/
		String uri = request.getRequestURI();
		if(uri != null && uri.contains("/service/"))
			return true;

		/* 注解权限认证 */
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		Method method = handlerMethod.getMethod();
		Permission pm = method.getAnnotation(Permission.class);
		if (pm != null) {
			if (pm.action() == Action.Skip) {
				/* 忽略拦截 */
				return true;
			} else if(StringUtils.isNotBlank(pm.value()) && authorization.isPermitted(token, pm.value())) {
				/* 权限合法 */
				return true;
			}
		}
		/* 非法访问 */
		return false;
	}

	/**
	 * @desc 无权限访问处理,默认返回 403,illegalUrl 非空重定向至该地址
	 * @param request http请求对象
	 * @param response http响应对象
	 * @return 验证不通过,无权限访问
	 * @throws Exception
	 */
	protected boolean unauthorizedAccess(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logger.info(" request 403 url: " + request.getRequestURI());

		// AJAX 请求 403 未授权访问提示
		if (HttpUtils.isAjax(request)) {
			HttpUtils.ajaxStatus(response, 403, "ajax Unauthorized access.");
		} else {
			// 正常 HTTP 请求
			if(StringUtils.isNotBlank(illegalUrl)) {
				response.sendRedirect(illegalUrl);
			} else {
				response.sendError(403, "Forbidden");
			}
		}
		return false;
	}

	public ISSOAuthorization getAuthorization() {
		return authorization;
	}

	public void setAuthorization(ISSOAuthorization authorization) {
		this.authorization = authorization;
	}

	public String getIllegalUrl() {
		return illegalUrl;
	}

	public void setIllegalUrl(String illegalUrl) {
		this.illegalUrl = illegalUrl;
	}
}